package com.hoas.comparedb.core;


import com.hoas.comparedb.entity.Table;
import com.hoas.comparedb.entity.TableColumn;
import com.hoas.comparedb.entity.TableIndex;
import com.hoas.comparedb.pojo.TableChange;
import com.hoas.comparedb.pojo.TableColumnDiffItem;
import com.hoas.comparedb.pojo.TableDiffItem;
import com.hoas.comparedb.pojo.TableIndexDiffItem;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

public class DBCompare {

    private DBReader soReader;

    private DBReader snReader;

    public DBCompare(DBReader soReader, DBReader snReader) {
        this.soReader = soReader;
        this.snReader = snReader;
    }


    public List<TableChange> compare() throws SQLException {

        List<Table> soTables = readTables( soReader, null);
        List<Table> snTables = readTables( snReader , null);

        List<TableChange> list = soTables.stream()
                .map( r -> {

                    if (snTables.contains( r )) {

                        // 修改表
                        Optional<Table> sn_table = snTables.stream().filter( t -> r.equals( t ) ).findFirst();
                        TableChange change = buildAlterTableChange(sn_table.get(), r);

                        return change;


                    } else {

                        // 新增表结构
                        TableChange change = new TableChange(r);
                        change.setTableDiff(new TableDiffItem( null, r));
                        return change;

                    }

                })
                .collect(Collectors.toList());

        return list;

    }

    private static List<Table> readTables(DBReader reader, String tableName) throws SQLException {
        List<Table> tables = reader.getTables( tableName );
        for (Table table : tables) {
            List<TableColumn> columns = reader.getColumns( table );
            table.setTableColumns( columns );

            List<TableIndex> indexes = reader.getIndexes( table );
            table.setTableIndexes( indexes );

        }

        return tables;
    }

    private TableChange buildAlterTableChange(Table sn_table, Table tb) {
        TableDiffItem tableDiff = new TableDiffItem(sn_table, tb);
        List<TableColumnDiffItem> columnDiff = new ArrayList<>();
        List<TableIndexDiffItem> indexDiff = new ArrayList<>();

        boolean tableChanged = false;


        for (TableColumn r : tb.getTableColumns()) {

            Optional<TableColumn> col = sn_table.getTableColumns().stream().filter(t -> t.getColumnName().equals(r.getColumnName())).findFirst();

            TableColumnDiffItem item = new TableColumnDiffItem(col.isPresent() ? col.get() : null, r);

            if ( item != null) {
                if (!columnDiff.contains( item )) {
                    columnDiff.add( item );
                    if (!TableColumnDiffItem.NO.equals(item.getType())) {
                        tableChanged = true;
                    }
                }

            }
        };

        for (TableColumn r : sn_table.getTableColumns()) {
            Optional<TableColumn> col = tb.getTableColumns().stream().filter(t -> t.getColumnName().equals(r.getColumnName())).findFirst();
            TableColumnDiffItem item = new TableColumnDiffItem( r, col.isPresent() ? col.get() : null);

            if ( item != null && !TableColumnDiffItem.NO.equals(item.getType())) {
                if (!columnDiff.contains(item)) {
                    columnDiff.add(item);
                    if (!TableColumnDiffItem.NO.equals(item.getType())) {
                        tableChanged = true;
                    }
                }
            }
        }

        for (TableIndex r : tb.getTableIndexes()) {
            Optional<TableIndex> idx = sn_table.getTableIndexes()
                    .stream().
                    filter(t -> t.getIndexName().equals(r.getIndexName()))
                    .findFirst();
            TableIndexDiffItem item = new TableIndexDiffItem(idx.isPresent() ? idx.get() : null, r);
            if ( item != null) {
                if (!indexDiff.contains( item )) {
                    indexDiff.add( item );
                    if ( !TableIndexDiffItem.NO.equals(item.getType()) ) {
                        tableChanged = true;
                    }
                }

            }
        }

        for (TableIndex r : sn_table.getTableIndexes()) {
            Optional<TableIndex> idx = tb.getTableIndexes().stream().filter(t -> t.getIndexName().equals(r.getIndexName())).findFirst();

            TableIndexDiffItem item = new TableIndexDiffItem( r, idx.isPresent() ? idx.get() : null);

            if ( item  != null ) {
                if (!indexDiff.contains( item )) {
                    indexDiff.add( item );

                    if ( !TableIndexDiffItem.NO.equals(item.getType()) ) {
                        tableChanged = true;
                    }
                }
            }

        }

        TableChange change = new TableChange( tb );
        change.setTableDiff( tableDiff );
        change.setColumnDiffs( columnDiff );
        change.setIndexDiffs( indexDiff );
        if (tableChanged) {
            tableDiff.setType( TableDiffItem.ALTER );
        }

        return change;
    }

    public DBReader getSoReader() {
        return soReader;
    }

    public DBReader getSnReader() {
        return snReader;
    }

}
